#!/usr/bin/env python3
"""
图片格式转换器 - 交互式构建脚本
运行后直接选择参数进行可执行文件打包

用法:
    python build.py

无需命令行参数，通过交互界面选择配置
"""

import os
import platform
import shutil
import sys
import subprocess
from pathlib import Path

class BuildConfig:
    """构建配置类"""
    
    def __init__(self):
        self.project_name = "Image Format Converter"
        self.main_script = "main.py"
        self.project_root = Path(__file__).parent
        self.dist_dir = self.project_root / "dist"
        self.build_dir = self.project_root / "build"
        self.spec_dir = self.project_root / "spec"
        
    def get_version(self):
        """从pyproject.toml获取版本号"""
        try:
            import tomllib
            with open(self.project_root / "pyproject.toml", "rb") as f:
                data = tomllib.load(f)
                return data.get("project", {}).get("version", "1.0.0")
        except:
            return "1.0.0"

class BuildManager:
    """构建管理器"""
    
    def __init__(self, config: BuildConfig):
        self.config = config
        
    def check_dependencies(self):
        """检查必要的依赖"""
        try:
            import PyInstaller
            print("✓ PyInstaller 已安装")
        except ImportError:
            print("✗ PyInstaller 未安装，正在安装...")
            subprocess.check_call([sys.executable, "-m", "pip", "install", "pyinstaller"])
            
    def clean_build(self):
        """清理构建缓存"""
        print("正在清理构建缓存...")
        for dir_path in [self.config.dist_dir, self.config.build_dir, self.config.spec_dir]:
            if dir_path.exists():
                shutil.rmtree(dir_path)
                print(f"已删除: {dir_path}")
                
    def generate_icon(self):
        """生成应用图标（根据操作系统选择对应格式）
        
        根据当前操作系统选择对应的图标文件格式：
        - Windows: .ico 格式
        - macOS: .icns 格式
        - Linux: .png 格式
        
        Returns:
            str: 图标文件路径，如果未找到则返回None
        """
        system = platform.system()
        icons_dir = self.config.project_root / "assets" / "icons"
        
        # 根据操作系统选择图标格式
        icon_formats = {
            "Windows": "icon.ico",
            "Darwin": "icon.icns",  # macOS
            "Linux": "icon.png"
        }
        
        icon_filename = icon_formats.get(system, "icon.ico")
        icon_path = icons_dir / icon_filename
        
        if icon_path.exists():
            print(f"✓ 找到{system}图标文件: {icon_path}")
            return str(icon_path)
        
        # 回退检查项目根目录
        fallback_path = self.config.project_root / icon_filename
        if fallback_path.exists():
            print(f"提示: 使用项目根目录图标: {fallback_path}")
            return str(fallback_path)
            
        print(f"提示: 未找到 {icon_filename}，将使用默认图标")
        return None
        
    def build_executable(self, arch: str, mode: str, console: bool, clean: bool, output_format: str):
        """构建可执行文件或安装包"""
        
        if clean:
            self.clean_build()
            
        self.check_dependencies()
        
        # 基础构建参数
        cmd = [
            sys.executable, "-m", "PyInstaller",
            "--name", f"{self.config.project_name}-{arch}",
            "--distpath", str(self.config.dist_dir),
            "--workpath", str(self.config.build_dir),
            "--specpath", str(self.config.spec_dir),
            "--noconfirm"
        ]
        
        # 架构相关配置
        arch_flags = {
            "x64": ["--target-arch", "x86_64"],
            "x86": ["--target-arch", "x86"],
            "arm64": ["--target-arch", "arm64"]
        }
        
        if arch in arch_flags:
            cmd.extend(arch_flags[arch])
            
        # 打包模式
        if mode == "onefile":
            cmd.append("--onefile")
        else:
            cmd.append("--onedir")
            
        # 控制台窗口
        if not console:
            cmd.append("--noconsole")
            
        # 添加隐藏导入（解决可能的导入问题）
        hidden_imports = [
            "PIL._imaging", "PIL._imagingft", "PIL._webp",
            "PySide6.QtCore", "PySide6.QtGui", "PySide6.QtWidgets"
        ]
        
        for imp in hidden_imports:
            cmd.extend(["--hidden-import", imp])
            
        # 添加数据文件
        data_files = [
            ("src", "src"),
            ("requirements.txt", ".")
        ]
        
        for src, dst in data_files:
            src_path = self.config.project_root / src
            if src_path.exists():
                cmd.extend(["--add-data", f"{src_path}{os.pathsep}{dst}"])
                
        # 图标
        icon_path = self.generate_icon()
        if icon_path:
            cmd.extend(["--icon", icon_path])
            
        # 主脚本
        cmd.append(str(self.config.project_root / self.config.main_script))
        
        # 根据输出格式调整参数
        if output_format in ["dmg", "app"]:
            # macOS特定配置
            cmd.extend(["--osx-bundle-identifier", "cn.skstudio.imageformatconverter"])
        elif output_format in ["deb", "rpm"]:
            # Linux安装包配置
            cmd.extend([
                "--linux-onefile",
                "--target-arch", arch
            ])
        elif output_format == "installer":
            # Windows安装程序配置
            cmd.extend(["--version-file", str(self.config.project_root / "version_info.txt")])
        
        print(f"开始构建 {arch} 架构的{mode}包...")
        print(f"命令: {' '.join(cmd)}")
        
        try:
            subprocess.check_call(cmd)
            
            # 根据输出格式处理结果
            base_name = f"{self.config.project_name}-{arch}"
            
            if output_format == "dmg" and platform.system() == "Darwin":
                # 创建macOS dmg安装包
                dmg_path = self.create_macos_dmg(base_name)
                if dmg_path:
                    print(f"✓ 构建成功！输出路径: {dmg_path}")
                    return str(dmg_path)
            elif output_format == "app" and platform.system() == "Darwin":
                # macOS .app格式
                app_path = self.config.dist_dir / f"{base_name}.app"
                if app_path.exists():
                    print(f"✓ 构建成功！输出路径: {app_path}")
                    return str(app_path)
            elif output_format in ["deb", "rpm"] and platform.system() == "Linux":
                # Linux安装包
                package_path = self.create_linux_package(base_name, output_format)
                if package_path:
                    print(f"✓ 构建成功！输出路径: {package_path}")
                    return str(package_path)
            else:
                # 可执行文件（Windows/Linux/macOS）
                if platform.system() == "Windows":
                    exe_path = self.config.dist_dir / f"{base_name}.exe"
                    if exe_path.exists():
                        print(f"✓ 构建成功！输出路径: {exe_path}")
                        return str(exe_path)
                else:
                    # Linux/macOS可执行文件
                    exe_path = self.config.dist_dir / base_name
                    if exe_path.exists():
                        print(f"✓ 构建成功！输出路径: {exe_path}")
                        return str(exe_path)
                print("✗ 构建失败：输出文件未找到")
                return None
                
        except subprocess.CalledProcessError as e:
            print(f"✗ 构建失败: {e}")
            return None
            
    def create_macos_dmg(self, base_name: str):
        """创建macOS dmg安装包"""
        try:
            app_path = self.config.dist_dir / f"{base_name}.app"
            if not app_path.exists():
                return None
                
            dmg_path = self.config.dist_dir / f"{base_name}.dmg"
            print(f"正在创建macOS安装包: {dmg_path}")
            
            # 这里可以添加创建dmg的逻辑
            # 由于需要额外的工具，这里简化处理
            return str(app_path)  # 暂时返回.app路径
            
        except Exception as e:
            print(f"创建dmg失败: {e}")
            return None
            
    def create_linux_package(self, base_name: str, package_format: str):
        """创建Linux安装包"""
        try:
            executable_path = self.config.dist_dir / base_name
            if not executable_path.exists():
                return None
                
            package_path = self.config.dist_dir / f"{base_name}.{package_format}"
            print(f"正在创建Linux安装包: {package_path}")
            
            # 这里可以添加创建deb/rpm的逻辑
            # 由于需要额外的工具，这里简化处理
            return str(executable_path)  # 暂时返回可执行文件路径
            
        except Exception as e:
            print(f"创建{package_format}包失败: {e}")
            return None

def main():
    """交互式构建主函数"""
    config = BuildConfig()
    builder = BuildManager(config)
    
    print("=" * 60)
    print("图片格式转换器 - 交互式构建工具")
    print(f"版本: {config.get_version()}")
    print("=" * 60)
    
    # 智能检测当前平台架构作为默认值
    import platform
    system = platform.system()
    machine = platform.machine()
    
    # 根据当前平台确定默认架构
    if system == "Windows":
        if machine == "AMD64":
            default_arch = "x64"
        elif machine == "x86":
            default_arch = "x86"
        elif machine == "ARM64":
            default_arch = "arm64"
        else:
            default_arch = "x64"
    elif system == "Darwin":  # macOS
        if machine == "x86_64":
            default_arch = "x64"
        elif machine == "arm64":
            default_arch = "arm64"
        else:
            default_arch = "x64"
    else:  # Linux
        if machine == "x86_64":
            default_arch = "x64"
        elif machine == "i386":
            default_arch = "x86"
        elif machine == "aarch64" or machine == "arm64":
            default_arch = "arm64"
        else:
            default_arch = "x64"
    
    # 交互式选择目标架构（支持跨平台构建）
    print(f"\n✅ 当前平台: {system} {machine}")
    print("请选择目标架构 (输入q或quit退出):")
    print("1. x64 (64位)")
    print("2. x86 (32位)")
    print("3. arm64 (ARM64)")
    
    arch_map = {"1": "x64", "2": "x86", "3": "arm64"}
    default_choice = "1" if default_arch == "x64" else ("2" if default_arch == "x86" else "3")
    
    while True:
        choice = input(f"请输入选项 (1-3) [默认: {default_choice}]: ").strip() or default_choice
        if choice.lower() in ['q', 'quit', 'exit']:
            print("构建已取消")
            sys.exit(0)
        if choice in arch_map:
            arch = arch_map[choice]
            break
        print("❌ 无效选择，请重新输入 (输入q退出)")
    
    # 交互式选择打包模式
    print("\n请选择打包模式 (输入q或quit退出):")
    print("1. 单文件 (onefile) - 生成单个exe文件")
    print("2. 目录 (onedir) - 生成包含依赖的文件夹")
    
    mode_map = {"1": "onefile", "2": "onedir"}
    while True:
        choice = input("请输入选项 (1-2) [默认: 1]: ").strip() or "1"
        if choice.lower() in ['q', 'quit', 'exit']:
            print("构建已取消")
            sys.exit(0)
        if choice in mode_map:
            mode = mode_map[choice]
            break
        print("❌ 无效选择，请重新输入 (输入q退出)")
    
    # 交互式选择输出格式
    print("\n请选择输出格式 (输入q或quit退出):")
    print("1. 可执行文件 (推荐)")
    
    system = platform.system()
    if system == "Darwin":  # macOS
        print("2. macOS安装包 (.dmg)")
        print("3. macOS应用包 (.app)")
        format_options = {"1": "executable", "2": "dmg", "3": "app"}
    elif system == "Linux":
        print("2. Linux安装包 (.deb)")
        print("3. Linux安装包 (.rpm)")
        format_options = {"1": "executable", "2": "deb", "3": "rpm"}
    else:  # Windows
        print("2. Windows安装程序 (.exe)")
        format_options = {"1": "executable", "2": "installer"}
    
    while True:
        choice = input("请输入选项 (1-3) [默认: 1]: ").strip() or "1"
        if choice.lower() in ['q', 'quit', 'exit']:
            print("构建已取消")
            sys.exit(0)
        if choice in format_options:
            output_format = format_options[choice]
            break
        print("❌ 无效选择，请重新输入 (输入q退出)")
    
    # 交互式选择是否显示控制台
    print("\n请选择控制台窗口 (输入q或quit退出):")
    print("1. 隐藏控制台窗口 (推荐)")
    print("2. 显示控制台窗口 (调试模式)")
    
    console_map = {"1": False, "2": True}
    while True:
        choice = input("请输入选项 (1-2) [默认: 1]: ").strip() or "1"
        if choice.lower() in ['q', 'quit', 'exit']:
            print("构建已取消")
            sys.exit(0)
        if choice in console_map:
            console = console_map[choice]
            break
        print("❌ 无效选择，请重新输入 (输入q退出)")
    
    # 交互式选择是否清理缓存
    print("\n是否清理之前的构建缓存 (输入q或quit退出)?")
    print("1. 保留缓存 (加快构建速度)")
    print("2. 清理缓存 (推荐首次构建)")
    
    clean_map = {"1": False, "2": True}
    while True:
        choice = input("请输入选项 (1-2) [默认: 1]: ").strip() or "1"
        if choice.lower() in ['q', 'quit', 'exit']:
            print("构建已取消")
            sys.exit(0)
        if choice in clean_map:
            clean = clean_map[choice]
            break
        print("❌ 无效选择，请重新输入 (输入q退出)")
    
    # 确认构建参数
    format_names = {
        "executable": "可执行文件",
        "dmg": "macOS安装包(.dmg)",
        "app": "macOS应用包(.app)",
        "deb": "Linux安装包(.deb)",
        "rpm": "Linux安装包(.rpm)",
        "installer": "Windows安装程序(.exe)"
    }
    
    print("\n" + "=" * 40)
    print("构建参数确认:")
    print(f"目标架构: {arch} (自动检测)")
    print(f"打包模式: {mode}")
    print(f"输出格式: {format_names.get(output_format, output_format)}")
    print(f"控制台窗口: {'显示' if console else '隐藏'}")
    print(f"清理缓存: {'是' if clean else '否'}")
    print("=" * 40)
    
    while True:
        confirm = input("\n确认开始构建? (y/n/q) [默认: y]: ").strip().lower() or "y"
        if confirm == "y":
            break
        elif confirm == "n":
            print("构建已取消")
            return
        elif confirm == "q":
            print("构建已取消")
            sys.exit(0)
        else:
            print("请输入 y, n 或 q (退出)")
    
    # 开始构建
    print("\n🚀 开始构建...")
    result = builder.build_executable(
        arch=arch,
        mode=mode,
        console=console,
        clean=clean,
        output_format=output_format
    )
    
    if result:
        print(f"\n🎉 构建完成！")
        print(f"📁 输出目录: {result}")
        print(f"💡 提示: 将生成的可执行文件发送给用户即可运行，无需安装Python环境")
        
        # 询问是否打开输出目录
        open_dir = input("\n是否打开输出目录? (y/n) [默认: n]: ").strip().lower() or "n"
        if open_dir == "y":
            import subprocess
            if os.name == 'nt':  # Windows
                subprocess.run(['explorer', str(Path(result).parent)])
    else:
        print(f"\n❌ 构建失败，请检查错误信息")
        sys.exit(1)

if __name__ == "__main__":
    main()